import React, { useContext, useMemo } from 'react';
import NavContext, { NavContextProps } from './NavContext';
import Menubar from '@/internals/Menu/Menubar';
import NavDropdown from './NavDropdown';
import NavMenu from './NavMenu';
import NavMegaMenu from './NavMegaMenu';
import NavDropdownItem from './NavDropdownItem';
import NavDropdownMenu from './NavDropdownMenu';
import AdaptiveNavItem from './AdaptiveNavItem';
import Box, { BaseBoxProps } from '@/internals/Box';
import { forwardRef, deprecateComponent } from '@/internals/utils';
import { useStyles, useCustom, useEnsuredRef, useControlled } from '@/internals/hooks';
import { NavbarContext } from '../Navbar/NavbarContext';
import { SidenavContext } from '../Sidenav/SidenavContext';
import type { HTMLPropsWithoutSelect } from '@/internals/types';

export interface NavProps<T = any> extends BaseBoxProps, HTMLPropsWithoutSelect {
  /**
   * The appearance style of the Nav component.
   * - 'pills' appearance is deprecated. Use `SegmentedControl` component instead.
   * @default 'default'
   */
  appearance?: 'default' | 'subtle' | 'tabs';

  /**
   * Whether the Nav component is reversed.
   */
  reversed?: boolean;

  /**
   * Whether the Nav component is justified.
   */
  justified?: boolean;

  /**
   * Whether the Nav component is vertical.
   */
  vertical?: boolean;

  /**
   * Whether the Nav component is pulled to the right.
   *
   * @deprecated Use `Navbar.Content` instead.
   */
  pullRight?: boolean;

  /**
   * The active key of the Nav component.
   */
  activeKey?: T;

  /**
   * The default active key of the Nav component.
   */
  defaultActiveKey?: T;

  /**
   * Event handler for selecting a Nav item.
   */
  onSelect?: (eventKey: T | undefined, event: React.SyntheticEvent) => void;
}

const DeprecatedNavDropdown = deprecateComponent(
  NavDropdown,
  '<Nav.Dropdown> is deprecated, use <Nav.Menu> instead.'
);
DeprecatedNavDropdown.Menu = deprecateComponent(
  NavDropdownMenu,
  '<Nav.Dropdown.Menu> is deprecated, use <Nav.Menu> instead'
);
DeprecatedNavDropdown.Item = deprecateComponent(
  NavDropdownItem,
  '<Nav.Dropdown.Item> is deprecated, use <Nav.Item> instead'
);

const Subcomponents = {
  /**
   * @deprecated Use <Nav.Menu> instead.
   */
  Dropdown: DeprecatedNavDropdown,
  Item: AdaptiveNavItem,
  Menu: NavMenu,
  MegaMenu: NavMegaMenu
};

/**
 * The `Nav` component is used to create navigation links.
 * @see https://rsuitejs.com/components/nav
 */
const Nav = forwardRef<'div', NavProps, typeof Subcomponents>((props, ref) => {
  const { propsWithDefaults } = useCustom('Nav', props);
  const {
    as,
    classPrefix = 'nav',
    appearance = 'default',
    vertical,
    justified,
    reversed,
    className,
    children,
    activeKey: activeKeyProp,
    defaultActiveKey,
    onSelect: onSelectProp,
    ...rest
  } = propsWithDefaults;

  const sidenav = useContext(SidenavContext);

  // Whether inside a <Navbar>
  const navbar = useContext(NavbarContext);

  const menubarRef = useEnsuredRef(ref);

  const { withPrefix, merge, rootPrefix, prefix } = useStyles(classPrefix);

  const classes = merge(
    className,
    rootPrefix({ 'navbar-nav': navbar, 'sidenav-nav': sidenav }),
    withPrefix()
  );

  const dataAttributes = {
    'data-appearance': appearance,
    'data-reversed': reversed,
    'data-justified': justified,
    'data-direction': vertical || sidenav ? 'vertical' : 'horizontal'
  };

  const { activeKey: activeKeyFromSidenav, onSelect: onSelectFromSidenav } = sidenav || {};

  const [activeKey, setActiveKey] = useControlled(
    activeKeyProp ?? activeKeyFromSidenav,
    defaultActiveKey
  );
  const contextValue = useMemo<NavContextProps>(
    () => ({
      activeKey,
      onSelect: (eventKey: string | number | undefined, event: React.SyntheticEvent) => {
        setActiveKey(eventKey);
        onSelectProp?.(eventKey, event);
        onSelectFromSidenav?.(eventKey, event);
      }
    }),
    [activeKey, onSelectFromSidenav, onSelectProp, setActiveKey]
  );

  if (sidenav?.expanded) {
    return (
      <NavContext.Provider value={contextValue}>
        <ul ref={ref as any} className={classes} {...dataAttributes} {...rest}>
          {children}
        </ul>
      </NavContext.Provider>
    );
  }

  const hasWaterline = appearance !== 'default';

  // If inside a collapsed <Sidenav>, render an ARIA `menubar` (vertical)
  if (sidenav) {
    return (
      <NavContext.Provider value={contextValue}>
        <Menubar vertical={!!sidenav}>
          {(menubar, ref) => (
            <Box as={as} ref={ref} className={classes} {...dataAttributes} {...menubar} {...rest}>
              {children}
            </Box>
          )}
        </Menubar>
      </NavContext.Provider>
    );
  }
  return (
    <NavContext.Provider value={contextValue}>
      <Box as={as} ref={menubarRef} className={classes} {...dataAttributes} {...rest}>
        {children}
        {hasWaterline && <div className={prefix('bar')} />}
      </Box>
    </NavContext.Provider>
  );
}, Subcomponents);

Nav.displayName = 'Nav';

export default Nav;
